package com.apes.fn.fico.expense;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.fico.expense.platformFee.PlatformFeeFactory;
import com.apes.fn.fico.expense.platformFee.PlatformFeeProcess;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.repository.RetailOrderPayMethodRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.fn.scm.retailOrder.service.tc.commission.EmployeeCommissionService;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.query.QueryService;
import com.apes.framework.query.SqlService;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.finance.model.IncomeType;
import com.apes.scm.masterdata.finance.repository.IncomeTypeRepository;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.rbac.repository.UserRepository;
import org.hibernate.query.internal.NativeQueryImpl;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

@Service("expenseService")
public class ExpenseService extends DomainService {

    @Autowired
    ExpenseRepository expenseRepository;

    @Autowired
    private PartyRoleRepository partyRoleRepository;

    @Autowired
    private RetailOrderRepository retailOrderRepository;

    @Autowired
    private IncomeTypeRepository incomeTypeRepository;

    @Autowired
    private EmployeeCommissionService employeeCommissionService;

    @Autowired
    private RetailOrderPayMethodRepository retailOrderPayMethodRepository;

    @Autowired
    private DeptRepository deptRepository;

    @Autowired
    private ExpenseItemDetailsBillRepository expenseItemDetailsBillRepository;

    @Autowired
    private ExpenseItemDetailsRepository expenseItemDetailsRepository;

    @Autowired
    private EnumerationRepository enumerationRepository;

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private SqlService sqlService;

    /***
     * 创建
     * @param request
     * @return
     */
    public Expense create(SimpleRequest request) {
        Expense expense = request.getO(Expense.class);
        if("approve".equals(expense.getState())) throw new RuntimeException("操作失败,请重新创建");
        expense.setState("create");
        expense.computeAmt();
        return expenseRepository.saveAndFlush(expense);
    }

    /***
     * 创建
     * @param request
     * @return
     */
    public Expense createRewardPunish(SimpleRequest request) {
        Expense expense = request.getO(Expense.class);
        if("approve".equals(expense.getState())) throw new RuntimeException("操作失败,请重新创建");
        expense.setState("create");
        expense.computeAmt();
        expense = expenseRepository.saveAndFlush(expense);
        SpringManager.getBean(ApesLoggerService.class).sendSynEvent("event:ir.logger.save", MapUtil.mapper(
                "businessType","Expense" , "businessKey", expense.getId(), "operate", "创建费用单", "workPostName",null,
                "operator_id", userRepository.findByOrigin(expense.get_creator().getId()).getId()));
        expense.setWrite(false);
        return expense;
    }

    /***
     * 更新
     * @param request
     * @return
     */
    public Expense update(SimpleRequest request) {
        isVaild(request, expenseRepository);

        Expense expense = request.getO(Expense.class);
        expense.computeAmt();
        return expenseRepository.saveAndFlush(expense);

    }

    /***
     * 删除
     * @param request
     * @return
     */
    public Expense delete(SimpleRequest request) {
        isVaild(request, expenseRepository);
        Expense expense = request.getO(Expense.class);
        if (expense.getRemark() != null) {
            if ("原平台费用单".equals(expense.getRemark().substring(0, 6))) {
                Expense reversalExpense = expenseRepository.findOne(expense.getRemark().substring(7));
                reversalExpense.setState("approve");
                reversalExpense.setRemark(null);
                expenseRepository.saveAndFlush(reversalExpense);
            }
        }
        expense.setState("delete");
        return expenseRepository.saveAndFlush(expense);
    }

    /***
     * 申请
     */
    public Expense apply(SimpleRequest request) {
        isVaild(request, expenseRepository);

        Expense expense = request.getO(Expense.class);

        Expense expenseOne = expenseRepository.findOne(expense.getId());
        if ("apply".equals(expenseOne.getState()) && "apply".equals(expense.getState())) throw new RuntimeException("当前单据已申请，请刷新！");
        expense.setState("apply");
        expense.setApplyId(request.getPerson());
        expense.setApplyDate(new Date());

        Expense flush = expenseRepository.saveAndFlush(expense);
        flush.setProcessInitiator(expense.getProcessInitiator());
        flush.setProcessInitiatingDepartment(expense.getProcessInitiatingDepartment());
        flush.setProcessInitiatingPost(expense.getProcessInitiatingPost());
        return flush;

    }

    /***
     * 审核
     */
    public Expense approve(SimpleRequest request) {
        isVaild(request, expenseRepository);

        Expense expense = request.getO(Expense.class);
        Expense expenseOne = expenseRepository.findOne(expense.getId());
        if ("approve".equals(expenseOne.getState()) && "approve".equals(expense.getState())) throw new RuntimeException("当前单据已审核，请刷新！");

        expense.setState("approve");
        expense.setApproveId(request.getPerson());
        expense.setApproveDate(new Date());
        this.createBills(expense);//回写费用账单
        return expenseRepository.saveAndFlush(expense);

    }

    /***
     * 奖惩费用单审核
     */
    public Expense approveRewardPunish(SimpleRequest request) {
        isVaild(request, expenseRepository);
        Expense expense = request.getO(Expense.class);

        Expense expenseOne = expenseRepository.findOne(expense.getId());
        if ("approve".equals(expenseOne.getState()) && "approve".equals(expense.getState())) throw new RuntimeException("当前单据已审核，请刷新！");

        expense.setState("approve");
        expense.setApproveId(expense.get_creator());
        expense.setApproveDate(new Date());
        this.createBills(expense);//回写费用账单
        SpringManager.getBean(ApesLoggerService.class).sendSynEvent("event:ir.logger.save", MapUtil.mapper(
                "businessType", "Expense", "businessKey", expense.getId(), "operate", "审核奖惩费用单", "workPostName",null,
                "operator_id", userRepository.findByOrigin(expense.getApproveId().getId()).getId()));
        expense = expenseRepository.saveAndFlush(expense);
        expense.setWrite(false);
        return expense;
    }

    /***
     * 费用单 系统审核
     */
    public Expense approveBySystem(SimpleRequest request) {
        isVaild(request, expenseRepository);
        Expense expense = request.getO(Expense.class);

        Expense expenseOne = expenseRepository.findOne(expense.getId());
        if ("approve".equals(expenseOne.getState()) && "approve".equals(expense.getState())) throw new RuntimeException("当前单据已审核，请刷新！");

        expense.setState("approve");
        expense.setApproveId(SpringManager.getBean(PartyRoleRepository.class).findOne("system"));
        expense.setApproveDate(new Date());
        this.createBills(expense);//回写费用账单
        return expenseRepository.saveAndFlush(expense);

    }

    /***
     * 平台服务费费用单 系统审核
     */
    public Expense approveFeeBySystem(SimpleRequest request) {
        Expense expense = request.getO(Expense.class);

        Expense expenseOne = expenseRepository.findOne(expense.getId());
        if ("approve".equals(expenseOne.getState()) && "approve".equals(expense.getState())) throw new RuntimeException("当前单据已审核，请刷新！");

        expense.setState("approve");
        expense.setApproveId(SpringManager.getBean(PartyRoleRepository.class).findOne("system"));
        expense.setApproveDate(new Date());
        this.createBills(expense);//回写费用账单
        return expenseRepository.saveAndFlush(expense);

    }

    /***
     * 审核拒绝
     */
    public Expense refuse(SimpleRequest request) {
        isVaild(request, expenseRepository);
        Expense expense = request.getO(Expense.class);
        expense.setState("create");
//        expense.setApproveId(request.getPerson());
//        expense.setApproveDate(new Date());
        return expenseRepository.saveAndFlush(expense);

    }

    /**
     * 冲红
     *
     * @param request
     * @return
     */
    public Expense stop(SimpleRequest request) {
        isVaild(request, expenseRepository);
        Expense expense = request.getO(Expense.class);
        if (!Objects.equals(expense.getState(), "approve")) {
            throw new RuntimeException("单据不为审核状态！无法冲红！");
        }
        if (expense.getExpenseItems().stream().mapToDouble(ExpenseItem::getWithholdingAmount).sum() != 0) {
            throw new RuntimeException("费用明细已经预扣收！无法冲红！");
        }
        expense.setApplyId(request.getPerson());

        Expense negativeExpense = createNegativeExpense(expense);
        expense.setState("reversal");
        expense.setRemark("冲红生成单据：" + negativeExpense.getId());
        expense.setApplyDate(new Date());
        expenseRepository.saveAndFlush(expense);
        negativeExpense.setProcessInitiator(expense.getProcessInitiator());
        negativeExpense.setProcessInitiatingDepartment(expense.getProcessInitiatingDepartment());
        negativeExpense.setProcessInitiatingPost(expense.getProcessInitiatingPost());
        return negativeExpense;
    }

    /**
     * 冲红重新生成平台费用单
     * @param expense
     * @return
     */
    private Expense createNegativeExpense(Expense expense) {
        Expense negativeExpense = new Expense();
        negativeExpense.setCreator(expense.getApplyId().getId());
        negativeExpense.setCreateDate(new Date());
        negativeExpense.setCompany(expense.getCompany());
        negativeExpense.setAmtTotal(expense.getAmtTotal() * -1);
        negativeExpense.setState("create");
        negativeExpense.setRemark("原平台费用单：" + expense.getId());
        negativeExpense.setExpenseItems(createNegativeExpenseItems(expense.getExpenseItems()));
        negativeExpense.setApplyId(expense.getApplyId());
        negativeExpense.setApplyDate(new Date());

        return expenseRepository.saveAndFlush(negativeExpense);
    }

    private List<ExpenseItem> createNegativeExpenseItems(List<ExpenseItem> expenseItems) {
        List<ExpenseItem> negativeExpenseItems = new ArrayList<>();
        expenseItems.forEach(expenseItem -> {
            ExpenseItem negativeExpenseItem = new ExpenseItem();
            negativeExpenseItem.setCompany(expenseItem.getCompany());
            negativeExpenseItem.setSettlePolicy(expenseItem.getSettlePolicy());
            negativeExpenseItem.setExpenseType(expenseItem.getExpenseType());
            negativeExpenseItem.setAmount(expenseItem.getAmount() * -1);
            negativeExpenseItem.setWithholdingAmount(expenseItem.getWithholdingAmount() * -1);
            negativeExpenseItem.setAmountDeducted(expenseItem.getAmountDeducted() * -1);
            negativeExpenseItem.setPeriodStart(expenseItem.getPeriodStart());
            negativeExpenseItem.setPeriodEnd(expenseItem.getPeriodEnd());
            negativeExpenseItem.setCalculateDate(expenseItem.getCalculateDate());
            negativeExpenseItem.setArrivalDate(expenseItem.getArrivalDate());
            negativeExpenseItem.setRemark(expenseItem.getRemark());
            negativeExpenseItem.setAnnex(expenseItem.getAnnex());
            negativeExpenseItem.setChannel(expenseItem.getChannel());
            negativeExpenseItem.setCarLicense(expenseItem.getCarLicense());
            negativeExpenseItem.setOrigin(expenseItem.getOrigin());
            negativeExpenseItem.setSource(expenseItem.getSource());
            negativeExpenseItems.add(negativeExpenseItem);
        });
        return negativeExpenseItems;
    }


    /***
     * 转对账
     */
    public Expense beforeCheck(SimpleRequest request) {
        Expense expense = request.getO(Expense.class);
        expense.setState("transCheck");
        return expenseRepository.saveAndFlush(expense);
    }


    /***
     * 对账
     */
    public Expense check(SimpleRequest request) {
        Expense expense = request.getO(Expense.class);
        expense.setState("check");
        expense.setCheckId(request.getPerson());
        expense.setCheckDate(new Date());
        return expenseRepository.saveAndFlush(expense);
    }


    /***
     * 清帐中
     */
    public Expense beforeClear(SimpleRequest request) {
        Expense expense = request.getO(Expense.class);
        expense.setState("transClear");
        return expenseRepository.saveAndFlush(expense);
    }

    /***
     * 清帐
     */
    public Expense clear(SimpleRequest request) {
        Expense expense = request.getO(Expense.class);
        expense.setState("clear");
        return expenseRepository.saveAndFlush(expense);
    }

    /***
     * 数据是否合法
     * @param request
     * @param repository
     */
    private Model isVaild(SimpleRequest request, CustomRepository repository) {
        Model oldModel = (Model) repository.findOne((String) request.get("id"));
        if (oldModel == null) throw new RuntimeException("单据【" + request.get("id") + "】在系统中不存在。");
        if (oldModel.getVersion() != (int) request.get("version")) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        return oldModel;
    }

    /**
     * 报表跳转查询单据用
     *
     * @param request
     * @return
     */
    public Expense findByExpesnId(SimpleRequest request) {
        String expense_id = request.get("EXPENSE_ID");
        return expenseRepository.findOne(expense_id);
    }

    /**
     * 支援确认单报表跳转查询单据用
     *
     * @param request
     * @return
     */
    public Expense findAffirmByExpenseId(SimpleRequest request) {
        String expense_id = request.get("GIVE_EXPENSE_ID");
        return expenseRepository.findOne(expense_id);
    }


    @OutboxSubscriber(id = "local:ExpenseService.createExpense", name = "建行生活零售单生成平台费用单")
    public void createExpense(OutboxPayloadWrapper outboxPayloadWrapper) throws Exception {
        String orderId = outboxPayloadWrapper.getAggregateId();
        RetailOrder retailOrder = retailOrderRepository.findById(orderId).get();
        //建行生活生成平台费用
        if (retailOrder.getChannel() == null) return;
        if (!"45".equals(retailOrder.getChannel().getId())) return;
        //付款类型为建行生活的客户
        String customerId = retailOrderPayMethodRepository.findByOrderId(retailOrder.getId()).getCustomer().getId();
        Map map = MapUtil.mapper("CHANNEL_ID", retailOrder.getChannel().getId(), "CUSTOMER_ID", customerId,
                "COMPANY_ID", retailOrder.getCompany().getId(),
                "OPERATION", retailOrder.getCompany().getParty().getCorporate().getOperation().getId());
        com.apestech.framework.json.JSONObject pop = employeeCommissionService.getStrategy(map, "POP");
        if (pop.get("sys_break") != null && pop.get("sys_break").equals("1")) return;
        PartyRole company = partyRoleRepository.findById("1007").get();
        Expense expense = new Expense();
        expense.setCompany(company);
        expense.setCreator("system");
        expense.setUserId("0");
        expense.setExpenseItems(createExpenseItem(retailOrder, pop));
        this.invoke("fn.expense.approveBySystem", MapUtil.mapped(this.invoke("fn.expense.create", MapUtil.mapped(expense))));
    }

    private List<ExpenseItem> createExpenseItem(RetailOrder retailOrder, com.apestech.framework.json.JSONObject pop) throws Exception {
        List<ExpenseItem> expenseItems = new ArrayList();
        ExpenseItem expenseItem = new ExpenseItem();
        //费用类型平台引流费
        IncomeType expenseType = incomeTypeRepository.findById("G17").get();
        //取POP店策略
        double p001 = pop.getDoubleValue("P001");
        expenseItem.setCompany(retailOrder.getCompany());
        expenseItem.setExpenseType(expenseType);
        expenseItem.setAmount(retailOrder.getAmtTotal() * p001);
        expenseItem.setPeriodEnd(retailOrder.getDateApprove());
        expenseItem.setPeriodStart(retailOrder.getDateApprove());
        expenseItem.setChannel(retailOrder.getChannel());
        expenseItem.setCarLicense(retailOrder.getCustomerExpand().getCarLicense());
        expenseItem.setOrigin(retailOrder.getOrderType());
        expenseItem.setSource(retailOrder.getId());
        expenseItems.add(expenseItem);
        return expenseItems;
    }

    public void createPlatformFee(SimpleRequest request) {
        String OrderType = request.get("ORDER_TYPE");
        PlatformFeeProcess platformFeeProcess = PlatformFeeFactory.get(OrderType);
        platformFeeProcess.process(request);
    }

    /**
     * 定时每天生成平台费用单
     */
    public void createPlatformFeeByTime(SimpleRequest request) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DAY_OF_MONTH, -1);
        Date yesterday = c.getTime();
        String date = DateUtil.format(yesterday, "yyyy-MM-dd");
        //分组查询出不同的公司
        List<String> companyIds = expenseItemDetailsBillRepository.findByCreateDate(date);
        if (companyIds.size() == 0) return;
        //每个公司一张平台费用单
        for (String companyId : companyIds) {
            //分组查询出不同的费用细项类型
            List<String> expenseDetailsTypes = expenseItemDetailsBillRepository.findByCompany(companyId, date);
            List<ExpenseItemDetails> expenseItemDetailsList = new ArrayList<>();
            List<ExpenseItem> expenseItems = new ArrayList<>();
            for (String expenseDetailsType : expenseDetailsTypes) {
                //根据公司和费用细项类型分组查询费用细项明细表
                List<ExpenseItemDetailsBill> expenseItemDetailsBills = expenseItemDetailsBillRepository.findByCompanyAndExpenseDetailsType(companyId, expenseDetailsType, date);
                //每个公司和费用细项类型生成一张费用明细细项表
                expenseItemDetailsList.add(createExpenseItemDetails(expenseItemDetailsBills));
            }
            //过滤出不同的费用类型
            List<IncomeType> incomeTypeList = expenseItemDetailsList.stream().map(ExpenseItemDetails::getIncomeType).distinct().collect(Collectors.toList());
            incomeTypeList.forEach(incomeType -> {
                //每个费用类型一张平台费用单明细单
                List<ExpenseItemDetails> newExpenseItemDetails = expenseItemDetailsList.stream().filter(expenseItemDetails -> incomeType.getId().equals(expenseItemDetails.getIncomeType().getId())).collect(Collectors.toList());
                if (newExpenseItemDetails.size() != 0)
                    expenseItems.add(createExpenseItem(newExpenseItemDetails, companyId, yesterday));
            });
            //生成平台费用单
            createExpenseFee(expenseItems);
        }
    }

    /**
     * 生成费用明细细项单
     */
    public ExpenseItemDetails createExpenseItemDetails(List<ExpenseItemDetailsBill> expenseItemDetailsBills) {
        ExpenseItemDetails expenseItemDetails = new ExpenseItemDetails();
        expenseItemDetails.setCompany(expenseItemDetailsBills.get(0).getCompany());
        expenseItemDetails.setIncomeType(expenseItemDetailsBills.get(0).getIncomeType());
        expenseItemDetails.setExpenseDetailsType(expenseItemDetailsBills.get(0).getExpenseDetailsType());
        expenseItemDetails.setPaymentAmount(expenseItemDetailsBills.stream().mapToDouble(ExpenseItemDetailsBill::getPaymentAmount).sum());
        expenseItemDetails.setExpenseAmount(expenseItemDetailsBills.stream().mapToDouble(ExpenseItemDetailsBill::getExpenseAmount).sum());
        expenseItemDetailsRepository.save(expenseItemDetails);
        expenseItemDetails.setExpenseItemDetailsBillList(expenseItemDetailsBills);
        return expenseItemDetails;
    }

    /**
     * 生成平台费用单明细
     */
    public ExpenseItem createExpenseItem(List<ExpenseItemDetails> expenseItemDetails, String companyId, Date date) {
        ExpenseItem expenseItem = new ExpenseItem();
        expenseItem.setExpenseItemDetailsList(expenseItemDetails);
        expenseItem.setCompany(partyRoleRepository.findOne(companyId));
        expenseItem.setExpenseType(expenseItemDetails.get(0).getIncomeType());
        expenseItem.setAmount(expenseItemDetails.stream().mapToDouble(ExpenseItemDetails::getExpenseAmount).sum());
        expenseItem.setPeriodStart(date);
        expenseItem.setPeriodEnd(date);
        expenseItem.setRemark("当日平台应收费用");
        return expenseItem;
    }

    /**
     * 生成平台费用单并自动审核
     */
    public void createExpenseFee(List<ExpenseItem> expenseItems) {
        Expense expense = new Expense();
        expense.setExpenseItems(expenseItems);
        expense.setCompany(partyRoleRepository.findOne("1007"));
        expense.setAmtTotal(expenseItems.stream().mapToDouble(ExpenseItem::getAmount).sum());
        expense.setCreator("system");
        expense.setUserId("0");
        this.invoke("fn.expense.approveFeeBySystem", this.invoke("fn.expense.create", expense));
    }

    public void expenseList(SimpleRequest request) {
        Map m = request.getMap();
        com.apestech.framework.json.JSONObject queryParam = new com.apestech.framework.json.JSONObject(m);
        queryParam.put("queryid", "fnExpense.query");

        request.setBody(queryParam.toString());
        SpringManager.getBean(QueryService.class).query(request);
    }

    /**
     * 平台费用细项分组查询数据
     * @param request
     * @return
     */
    public JSONObject expenseAmountList(SimpleRequest request) {
        JSONObject jsonObject = request.getJO();
        JSONArray conditionArray = (JSONArray)jsonObject.get("condition");

        //获取查询条件
        JSONObject jo = getCondition(conditionArray);
        String TENANT_ID = jo.containsKey("TENANT_ID") ? " AND C.COMPANY_ID = '" + jo.getString("TENANT_ID") + "'" : " AND 1 = 1 ";
        //费用周期起开始
        String PERIOD_BIGEND_START = jo.containsKey("PERIOD_BIGEND_START") ? " AND B.PERIOD_START >= to_date('" + jo.getString("PERIOD_BIGEND_START") + "','yyyy-MM-dd') " : "";
        //费用周期起结束
        String PERIOD_BIGEND_END = jo.containsKey("PERIOD_BIGEND_END") ? " AND B.PERIOD_START <= to_date('" + jo.getString("PERIOD_BIGEND_END") + "','yyyy-MM-dd')  " : "";
        //费用周期止开始
        String PERIOD_AFERT_START = jo.containsKey("PERIOD_AFTER_START") ? " AND B.PERIOD_END >= to_date('" + jo.getString("PERIOD_AFTER_START") + "','yyyy-MM-dd') " : "";
        //结束日期止结束
        String PERIOD_AFERT_END = jo.containsKey("PERIOD_AFTER_END") ? " AND B.PERIOD_END <= to_date('" + jo.getString("PERIOD_AFTER_END") + "','yyyy-MM-dd') " : "";
        StringBuffer sSql = new StringBuffer();
        sSql.append("SELECT T.*,'"+jo.getString("TENANT_ID")+"' AS TENANT_ID,'"+jo.getString("PERIOD_BIGEND_START")+"' AS PERIOD_BIGEND_START" +
                ", '"+jo.getString("PERIOD_BIGEND_END")+"' AS PERIOD_BIGEND_END,'"+jo.getString("PERIOD_AFTER_START")+"' AS PERIOD_AFTER_START" +
                ", '"+jo.getString("PERIOD_AFTER_END")+"' AS PERIOD_AFTER_END FROM (SELECT " +
                "        C.COMPANY_ID," +
                "        C.EXPENSE_DETAILS_TYPE," +
                "        SUM( C.PAYMENT_AMOUNT ) PAYMENT_AMOUNT," +
                "        SUM( C.EXPENSE_AMOUNT ) EXPENSE_AMOUNT," +
                "        (SELECT '[' || C.COMPANY_ID || ']' || A.NAME FROM MAS_PARTY_ROLE P,MAS_PARTY A WHERE P.ID = C.COMPANY_ID AND P.PARTY_ID = A.ID ) TENANT_NAME," +
                "        (SELECT '[' || C.INCOME_TYPE || ']' || I.NAME FROM MAS_INCOME_TYPE I WHERE I.ID = C.INCOME_TYPE ) EXPENSE_TYPE," +
                "        (SELECT M.DESCRIPTION FROM MAS_ENUMERATION M WHERE C.EXPENSE_DETAILS_TYPE = M.ID) DESCRIPTION\n" +
                "        FROM " +
                "        FN_EXPENSE_ITEM B," +
                "        FN_EXPENSE_ITEM_DETAILS C " +
                "        WHERE " +
                "        C.INCOME_TYPE = 'A09' AND C.EXPENSE_ITEM_ID = B.ID " +
                TENANT_ID + PERIOD_BIGEND_START + PERIOD_BIGEND_END + PERIOD_AFERT_START + PERIOD_AFERT_END +
                "        GROUP BY C.COMPANY_ID,C.EXPENSE_DETAILS_TYPE," +
                "        C.INCOME_TYPE,C.COMPANY_ID,C.EXPENSE_DETAILS_TYPE) T");
        Query query = entityManager.createNativeQuery(sSql.toString());
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        if (query.getResultList().size() == 0) throw new RuntimeException("未查询到结果");
        List<Map<String, Object>> listMap;
        listMap = query.getResultList();
        JSONObject data = handleData(listMap);
        return data;
    }

    /**
     * 平台费用细项封装查询条件
     * @param periodStartArray
     * @return
     */
    private JSONObject getCondition(JSONArray periodStartArray) {
        JSONObject jo = new JSONObject();
        if (!CollectionUtils.isEmpty(periodStartArray)) {
            for (int i = 0; i < periodStartArray.size(); i++) {
                JSONObject json = (JSONObject)periodStartArray.get(i);
                if (json.getString("field").equals("PERIOD_START")){
                    if(json.getString("operator").equals("GTE")){
                        jo.put("PERIOD_BIGEND_START", DateUtil.format(DateUtil.parse(json.getString("value")), "yyyy-MM-dd"));
                    }else {
                        jo.put("PERIOD_BIGEND_END", DateUtil.format(DateUtil.parse(json.getString("value")), "yyyy-MM-dd"));
                    }

                }
                if (json.getString("field").equals("PERIOD_END")){
                    if(json.getString("operator").equals("GTE")){
                        jo.put("PERIOD_AFTER_START", DateUtil.format(DateUtil.parse(json.getString("value")), "yyyy-MM-dd"));
                    }else {
                        jo.put("PERIOD_AFTER_END", DateUtil.format(DateUtil.parse(json.getString("value")), "yyyy-MM-dd"));
                    }
                }
                if (json.getString("field").equals("TENANT_ID")){
                    jo.put("TENANT_ID", json.getString("value"));
                }
            }
        }
        return jo;
    }

    /**
     * 平台费用细项封装返回数据
     * @param listMap
     * @return
     */
    private JSONObject handleData(List<Map<String, Object>> listMap) {
        JSONArray jsonArray = new JSONArray();
        if (!CollectionUtils.isEmpty(listMap)) {
            listMap.forEach(item -> {
                JSONObject jsonObject = new JSONObject();
                if (item.containsKey("COMPANY_ID")) jsonObject.put("COMPANY_ID", item.get("COMPANY_ID"));
                if (item.containsKey("EXPENSE_DETAILS_TYPE")) jsonObject.put("EXPENSE_DETAILS_TYPE", item.get("EXPENSE_DETAILS_TYPE"));
                if (item.containsKey("TENANT_NAME")) jsonObject.put("TENANT_NAME", item.get("TENANT_NAME"));
                if (item.containsKey("EXPENSE_TYPE")) jsonObject.put("EXPENSE_TYPE", item.get("EXPENSE_TYPE"));
                if (item.containsKey("DESCRIPTION")) jsonObject.put("DESCRIPTION", item.get("DESCRIPTION"));
                if (item.containsKey("PAYMENT_AMOUNT")) jsonObject.put("PAYMENT_AMOUNT", item.get("PAYMENT_AMOUNT"));
                if (item.containsKey("EXPENSE_AMOUNT")) jsonObject.put("EXPENSE_AMOUNT", item.get("EXPENSE_AMOUNT"));
                jsonArray.add(jsonObject);
            });
        }
        BigDecimal paymentAmount = listMap.stream().map(f -> new BigDecimal(f.get("PAYMENT_AMOUNT").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal EXPENSEAMOUNT = listMap.stream().map(f -> new BigDecimal(f.get("EXPENSE_AMOUNT").toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
        JSONArray footer = new JSONArray();
        JSONObject price = new JSONObject();
        price.put("PAYMENT_AMOUNT",paymentAmount.toString());
        price.put("EXPENSE_AMOUNT",EXPENSEAMOUNT.toString());
        footer.add(price);
        JSONObject response = new JSONObject();
        response.put("total", jsonArray.size());
        response.put("pages", 1);
        response.put("footer", footer);
        response.put("size", jsonArray.size());
        response.put("elements", jsonArray.size());
        response.put("content", jsonArray);
        return response;
    }


    /**
     * 平台费用单细项前端抽屉查询
     *
     * @param request
     * @return
     */
    public Map expenseAmount(SimpleRequest request) {
        JSONObject condition = request.get("data");
        JSONObject node = (JSONObject) condition.get("node");
        String id = node.get("EXPENSE_ITEM_ID").toString();
        List<Map> expenseItemDetailsList = expenseItemDetailsRepository.findAllByExpenseItemId(id);
        List<Map> listMap = new ArrayList<>();
        expenseItemDetailsList.forEach(expenseItemDetails -> {
            HashMap<Object, Object> map = new HashMap<>();
            map.putAll(expenseItemDetails);
            map.put("PERIOD_START", node.get("PERIOD_START"));
            map.put("PERIOD_END", node.get("PERIOD_END"));
            map.put("APPROVE_DATE", node.get("APPROVE_DATE"));
            map.put("TENANT_ID", node.get("TENANT_ID"));
            map.put("TENANT_NAME", node.get("TENANT_NAME"));
            map.put("EXPENSE_DETAILS_TYPE_NAME", enumerationRepository.findOne(map.get("EXPENSE_DETAILS_TYPE").toString()).getDescription());
            listMap.add(map);
        });
        int size = listMap.size();
        return MapUtil.mapper("content", listMap, "total", size, "size", size);
    }

    /**
     * 平台费用细项抽屉封装查询条件
     * @param condition
     * @return
     */
    private JSONObject getCondition(JSONObject condition) {
        JSONObject jo = new JSONObject();
        JSONObject node = (JSONObject) condition.get("node");
        if (!CollectionUtils.isEmpty(condition.getJSONArray("PERIOD_START"))){
            JSONArray periodStart = condition.getJSONArray("PERIOD_START");
            jo.put("PERIOD_BIGEND_START", DateUtil.format(DateUtil.parse(periodStart.getString(0)), "yyyy-MM-dd"));
            jo.put("PERIOD_BIGEND_END", DateUtil.format(DateUtil.parse(periodStart.getString(1)), "yyyy-MM-dd"));
        }
        if (!CollectionUtils.isEmpty(condition.getJSONArray("PERIOD_END"))){
            JSONArray periodEnd = condition.getJSONArray("PERIOD_END");
            jo.put("PERIOD_AFTER_START", DateUtil.format(DateUtil.parse(periodEnd.getString(0)), "yyyy-MM-dd"));
            jo.put("PERIOD_AFTER_END", DateUtil.format(DateUtil.parse(periodEnd.getString(1)), "yyyy-MM-dd"));
        }
        if (!ObjectUtils.isEmpty(node.get("COMPANY_ID"))){
            jo.put("COMPANY_ID", node.get("COMPANY_ID"));
        }
        if (!ObjectUtils.isEmpty(node.get("EXPENSE_DETAILS_TYPE"))){
            jo.put("EXPENSE_DETAILS_TYPE", node.get("EXPENSE_DETAILS_TYPE"));
        }
        return jo;
    }

    /**
     * 平台费用细项费用金额抽屉查询
     *
     * @param request
     * @return
     */
    public Map expenseAmountBillList(SimpleRequest request) {
        JSONObject condition = request.get("data");
        JSONObject jo = getCondition(condition);

        String EXPENSE_DETAILS_TYPE = jo.containsKey("EXPENSE_DETAILS_TYPE") ? " AND A.EXPENSE_DETAILS_TYPE = '"+jo.getString("EXPENSE_DETAILS_TYPE")+"'" : " AND 1 = 1 ";
        String TENANT_ID = jo.containsKey("COMPANY_ID") ? " AND A.COMPANY_ID = '"+jo.getString("COMPANY_ID")+"'" : " AND 1 = 1 ";
        //费用周期起开始
        String PERIOD_BIGEND_START = jo.containsKey("PERIOD_BIGEND_START") ? " AND B.PERIOD_START >= to_date('"+jo.getString("PERIOD_BIGEND_START")+"','yyyy-MM-dd') " : " AND 1 = 1 ";
        //费用周期起结束
        String PERIOD_BIGEND_END = jo.containsKey("PERIOD_BIGEND_END") ? " AND B.PERIOD_START <= to_date('"+jo.getString("PERIOD_BIGEND_END")+"','yyyy-MM-dd')  " : " AND 1 = 1 ";
        //费用周期止开始
        String PERIOD_AFERT_START = jo.containsKey("PERIOD_AFTER_START") ? " AND B.PERIOD_END >= to_date('"+jo.getString("PERIOD_AFTER_START")+"','yyyy-MM-dd') " : " AND 1 = 1 ";
        //结束日期止结束
        String PERIOD_AFERT_END = jo.containsKey("PERIOD_AFTER_END") ? " AND B.PERIOD_END <= to_date('"+jo.getString("PERIOD_AFTER_END")+"','yyyy-MM-dd') " : " AND 1 = 1 ";

        StringBuffer sSql = new StringBuffer();
        sSql.append("SELECT A.ID AID,A.COMPANY_ID ACOMPANY_ID,A.EXPENSE_DETAILS_TYPE AEXPENSE_DETAILS_TYPE,TO_CHAR(B.PERIOD_START,'yyyy-MM-dd') PERIOD_START,TO_CHAR(B.PERIOD_END,'yyyy-MM-dd') PERIOD_END,T.ID, \n" +
                "       T.CREATE_DATE, T.LAST_UPDATED_STAMP, T.UPDATE_DATE, T.EXPENSE_AMOUNT, ORDER_ID, ORDER_TYPE, \n" +
                "       T.PAYMENT_AMOUNT, T.SOURCE, SOURCE_BUSINESS_TYPE, (CASE SUMMARY WHEN '接案介绍费' THEN '定损介绍费' else SUMMARY end) SUMMARY, T.COMPANY_ID, DEPT_ID, \n" +
                "       T.EXPENSE_DETAILS_TYPE, EXPENSE_ITEM_DETAILS_ID, T.INCOME_TYPE, STATISTIC_DATE " +
                "           FROM FN_EXPENSE_ITEM_DETAILS A, FN_EXPENSE_ITEM B, FN_EXPENSE_ITEM_DETAILS_BILL T  " +
                "           WHERE T.expense_item_details_id = A.ID AND A.EXPENSE_ITEM_ID = B.ID AND A.INCOME_TYPE = 'A09' " +
                EXPENSE_DETAILS_TYPE + TENANT_ID + PERIOD_BIGEND_START + PERIOD_BIGEND_END + PERIOD_AFERT_START + PERIOD_AFERT_END
        );
        Query query = entityManager.createNativeQuery(sSql.toString());
        query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        if(query.getResultList().size() == 0) throw new RuntimeException("未查询到结果");
        List<Map> listMap;
        listMap = query.getResultList();

        List<Map> expenseItemDetailsBillList = new ArrayList<>();
        listMap.forEach(expenseItemDetailsBill -> {
            HashMap<Object, Object> map = new HashMap<>();
            map.putAll(expenseItemDetailsBill);
            map.put("ORDER_TYPE", findOrderType(expenseItemDetailsBill.get("ORDER_TYPE").toString()));
            map.put("CREATE_DATE", findOrderType(expenseItemDetailsBill.get("ORDER_TYPE").toString()));
            map.put("SOURCE_BUSINESS_TYPE", findSourceBusinessType(expenseItemDetailsBill.get("SOURCE_BUSINESS_TYPE").toString()));
            map.put("EXPENSE_DETAILS_TYPE_NAME", enumerationRepository.findOne(expenseItemDetailsBill.get("EXPENSE_DETAILS_TYPE").toString()).getDescription());
            map.put("INCOME_TYPE_NAME", incomeTypeRepository.findOne(expenseItemDetailsBill.get("INCOME_TYPE").toString()).getName());
            map.put("PERIOD_START",expenseItemDetailsBill.get("PERIOD_START").toString());
            map.put("PERIOD_END",expenseItemDetailsBill.get("PERIOD_END").toString());
            expenseItemDetailsBillList.add(map);
        });
        int size = expenseItemDetailsBillList.size();
        return MapUtil.mapper("content", expenseItemDetailsBillList, "total", size, "size", size);
    }


    /**
     * 平台费用单细项明细前端抽屉查询
     *
     * @param request
     * @return
     */
    public JSONObject expenseAmountBill(SimpleRequest request) throws ParseException {
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map ORDER_TYPE = MapUtil.mapper("field", "ORDER_TYPE",
                "headerName", "单据", "width", 90
        );
        tableHeader.add(ORDER_TYPE);

        Map ORDER_ID = MapUtil.mapper("field", "ORDER_ID",
                "headerName", "单号", "width", 150
        );
        tableHeader.add(ORDER_ID);

        Map SOURCE_BUSINESS_TYPE = MapUtil.mapper("field", "SOURCE_BUSINESS_TYPE",
                "headerName", "源单据", "width", 90
        );
        tableHeader.add(SOURCE_BUSINESS_TYPE);

        Map SOURCE = MapUtil.mapper("field", "SOURCE",
                "headerName", "源单号", "width", 150
        );
        tableHeader.add(SOURCE);

        Map INCOME_TYPE = MapUtil.mapper("field", "INCOME_TYPE_NAME",
                "headerName", "费用类型", "width", 100
        );

        tableHeader.add(INCOME_TYPE);
        Map EXPENSE_DETAILS_TYPE = MapUtil.mapper("field", "EXPENSE_DETAILS_TYPE_NAME",
                "headerName", "费用细项", "width", 100
        );
        tableHeader.add(EXPENSE_DETAILS_TYPE);

        Map SUMMARY = MapUtil.mapper("field", "SUMMARY",
                "headerName", "摘要", "width", 200
        );
        tableHeader.add(SUMMARY);

        Map PAYMENT_AMOUNT = MapUtil.mapper("field", "PAYMENT_AMOUNT",
                "headerName", "款项金额", "sum", "true", "width", 90
        );
        tableHeader.add(PAYMENT_AMOUNT);

        Map EXPENSE_AMOUNT = MapUtil.mapper("field", "EXPENSE_AMOUNT",
                "headerName", "费用金额", "sum", "true", "width", 90
        );
        tableHeader.add(EXPENSE_AMOUNT);

        JSONObject condition = request.get("data");
        JSONObject node = (JSONObject) condition.get("node");
        String id = node.get("ID").toString();
        List<Map> expenseItemDetailsBillList = expenseItemDetailsBillRepository.findByExpenseItemDetailsId(id);
        List<Map> listMap = new ArrayList<>();
        expenseItemDetailsBillList.forEach(expenseItemDetails -> {
            HashMap<Object, Object> map = new HashMap<>();
            map.putAll(expenseItemDetails);
            map.put("ORDER_TYPE", findOrderType(expenseItemDetails.get("ORDER_TYPE").toString()));
            map.put("SOURCE_BUSINESS_TYPE", findSourceBusinessType(expenseItemDetails.get("SOURCE_BUSINESS_TYPE").toString()));
            map.put("EXPENSE_DETAILS_TYPE_NAME", enumerationRepository.findOne(expenseItemDetails.get("EXPENSE_DETAILS_TYPE").toString()).getDescription());
            map.put("INCOME_TYPE_NAME", incomeTypeRepository.findOne(expenseItemDetails.get("INCOME_TYPE").toString()).getName());
            listMap.add(map);
        });
        object.put("tableHeader", tableHeader);
        object.put("content", listMap);
        return object;
    }

    public String findOrderType(String orderType) {
        switch (orderType) {
            case "AdvancePayment":
                orderType = "订金单";
                break;
            case "InsuranceOrder":
                orderType = "车险订单";
                break;
            case "MoneyIncome":
                orderType = "资金收入单";
                break;
            case "PolicyInformation":
                orderType = "车险保单";
                break;
            case "RetailOrder":
                orderType = "零售单";
                break;
            case "SettleExpense":
                orderType = "平台定损费用单";
                break;
            case "UsedCar":
                orderType = "二手车";
                break;
            case "VipUnionSettle":
                orderType = "会员联盟";
                break;
            case "Voucher":
                orderType = "业务凭证";
                break;
        }
        return orderType;
    }

    public String findSourceBusinessType(String sourceBusinessType) {
        switch (sourceBusinessType) {
            case "MoneyIncome":
                sourceBusinessType = "资金收入单";
                break;
            case "AdvancePayment":
                sourceBusinessType = "订金单";
                break;
            case "SaleOrder":
                sourceBusinessType = "分销订单";
                break;
            case "SaleReturn":
                sourceBusinessType = "分销退货订单";
                break;
            case "retailReturn":
                sourceBusinessType = "零售退货";
                break;
            case "RetailOrder":
            case "retailOrder":
                sourceBusinessType = "零售订单";
                break;
            case "ServicePlan":
            case "server":
                sourceBusinessType = "服务方案";
                break;
            case "CustomerConsignStatement":
                sourceBusinessType = "客户寄售对账单";
                break;
            case "Voucher":
                sourceBusinessType = "凭证订单";
                break;
            case "InternalHelpReturnApproval":
                sourceBusinessType = "內协退货申请审批单";
                break;
            case "WorkOrder":
                sourceBusinessType = "派工单";
                break;
            case "PriceChange":
                sourceBusinessType = "采购变价单";
                break;
            case "PurchaseOrder":
                sourceBusinessType = "采购订单";
                break;
            case "ePlus_Return":
                sourceBusinessType = "e服务+";
                break;
            case "LossQuotation":
            case "noDirectPay":
            case "directPay":
                sourceBusinessType = "直赔";
                break;
            case "yearcard":
                sourceBusinessType = "年卡";
                break;
            case "generalOrder":
                sourceBusinessType = "普通单";
                break;
            case "storedValue":
                sourceBusinessType = "储值单";
                break;
            case "DS0":
                sourceBusinessType = "老定损报价";
                break;
            case "yearCardReturn":
                sourceBusinessType = "年卡退回单";
                break;
            case "annualAudit":
                sourceBusinessType = "年审订单";
                break;
            case "replacement":
                sourceBusinessType = "兑换券置换";
                break;
        }
        return sourceBusinessType;
    }

    /**
     * 生成费用账单 并且审核
     *
     * @param expense
     */
    public void createBills(Expense expense) {
        // 根据明细上面的公司和主表的平台公司分组
        expense.getExpenseItems().stream()
                .collect(Collectors.groupingBy(ExpenseItem::getCompany))
                .forEach((company, expenseItemList) -> {
                    //根据费用类型种的费用类别拆分
                    expenseItemList.stream().collect(Collectors.groupingBy(ExpenseItem::getInComeCategory)).forEach((inComeCategory, expenseItems) -> {
                        // 收入生成费用账单
                        income(expense, inComeCategory, expenseItems);

                        //支出生成费用账单
                        outcome(expense, inComeCategory, expenseItems);
                    });

                });
    }

    private void income(Expense expense, Enumeration inComeCategory, List<ExpenseItem> expenseItemList) {
        List<Map> maps = new ArrayList<>();
        // 明细数据
        List<Map> items = expenseItemList.stream().map(expenseItem ->
                MapUtil.mapper("reconcileBeginDate", expenseItem.getPeriodStart(),
                        "reconcileEndDate", expenseItem.getPeriodEnd(), "amount", expenseItem.getAmount(),
                        "expenseType", expenseItem.getExpenseType().getId(), "note", expenseItem.getRemark(),
                        "source", expense.getId(), "annex", expenseItem.getAnnex(), "id", expenseItem.getId(),
                        "deptId", deptRepository.findByDeptTypeIdAndCompanyId("000006", expense.getCompany().getId()).getId(),
                        "company", expense.getCompany().getId(), "carLicense", expenseItem.getCarLicense(),
                        "partner", expenseItem.getCompany().getParty().getPartyRoleByType("Supplier").getId())
        ).collect(Collectors.toList());
        maps.add(MapUtil.mapper("creator", expense.getCreator(),"approveId",expense.getApproveId(),"list", items));
        this.invoke("income.incomeCreate", JSON.toJSONString((MapUtil.mapper("sourceBusinessType", "Expense", "remark", "平台费用！","state",expense.getState(),
                "inComeCategory", inComeCategory.getId(), "details", maps))));
    }

    private void outcome(Expense expense, Enumeration inComeCategory, List<ExpenseItem> expenseItemList) {
        List<Map> maps = new ArrayList<>();
        // 明细数据
        List<Map> items = expenseItemList.stream().map(expenseItem ->
                MapUtil.mapper("reconcileBeginDate", expenseItem.getPeriodStart(),
                        "reconcileEndDate", expenseItem.getPeriodEnd(), "amount", expenseItem.getAmount(),
                        "expenseType", expenseItem.getExpenseType().getId(), "note", expenseItem.getRemark(),
                        "source", expense.getId(), "annex", expenseItem.getAnnex(), "id", expenseItem.getId(),
                        "company", expenseItem.getCompany().getId(), "carLicense", expenseItem.getCarLicense(),
                        "deptId", deptRepository.findByDeptTypeIdAndCompanyId("000007", expenseItem.getCompany().getId()).getId(),
                        "partner", expense.getCompany().getParty().getPartyRoleByType("Customer").getId())
        ).collect(Collectors.toList());
        maps.add(MapUtil.mapper(
                "creator", expense.getCreator(),"approveId",expense.getApproveId(), "list", items));
        this.invoke("income.incomeCreate", JSON.toJSONString((MapUtil.mapper("sourceBusinessType", "Expense", "remark", "平台费用！","state",expense.getState(),
                "inComeCategory", inComeCategory.getId(), "details", maps))));
    }


}
